package net.cassite.daf4j.ds;

import net.cassite.daf4j.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * DataSource通用工具类
 */
public class DSUtils {
        private DSUtils() {
        }

        /**
         * list执行时的解析过程
         *
         * @param context        上下文
         * @param whereClause    条件语句
         * @param parameter      参数
         * @param parserPacket   解析器包
         * @param <Context>      上下文类型
         * @param <BasicElement> 基本元素类型
         * @param <DS>           数据源类型
         * @return 上下文
         * @throws Exception 可能的异常
         */
        public static <Context, BasicElement, DS> Context listGenerationProcess(Context context, Where whereClause, QueryParameter parameter, ParserPacket<Context, BasicElement, DS> parserPacket) throws Exception {
                context = parserPacket.aroundParser.beforeParsingList(context);
                context = parseSelectOperation(context, whereClause, parameter, parserPacket.aroundParser, parserPacket.andOrParser, parserPacket.conditionResolver, parserPacket.expressionResolver, parserPacket.queryParameterParser);
                context = parserPacket.aroundParser.afterParsingList(context);
                return context;
        }

        /**
         * projection执行时的解析过程
         *
         * @param context        上下文
         * @param whereClause    条件语句
         * @param parameter      参数
         * @param parserPacket   解析器包
         * @param <Context>      上下文类型
         * @param <BasicElement> 基本元素类型
         * @param <DS>           数据源类型
         * @return 上下文
         * @throws Exception 可能的异常
         */
        public static <Context, BasicElement, DS> Context projectionGenerationProcess(Context context, Where whereClause, QueryParameterWithFocus parameter, ParserPacket<Context, BasicElement, DS> parserPacket) throws Exception {
                DSUtils.parseQueryParameterWithFocus(context, parameter, parserPacket.aroundParser, parserPacket.queryParameterParser);
                context = parserPacket.aroundParser.beforeParsingProjection(context);
                context = DSUtils.parseSelectOperation(context, whereClause, parameter, parserPacket.aroundParser, parserPacket.andOrParser, parserPacket.conditionResolver, parserPacket.expressionResolver, parserPacket.queryParameterParser);
                context = parserPacket.aroundParser.afterParsingProjection(context);
                return context;
        }

        /**
         * update执行时的解析过程
         *
         * @param context        上下文
         * @param whereClause    条件语句
         * @param entries        更新项
         * @param parserPacket   解析器包
         * @param <Context>      上下文类型
         * @param <BasicElement> 基本元素类型
         * @param <DS>           数据源类型
         * @return 上下文
         * @throws Exception 可能的异常
         */
        public static <Context, BasicElement, DS> Context updateGenerationProcess(Context context, Where whereClause, UpdateEntry[] entries, ParserPacket<Context, BasicElement, DS> parserPacket) throws Exception {
                parserPacket.aroundParser.beforeParsingUpdate(context);
                parserPacket.aroundParser.beforeParsingWhere(context, whereClause);
                BasicElement elem = DSUtils.parseWhere(context, whereClause, parserPacket.andOrParser, parserPacket.conditionResolver, parserPacket.expressionResolver);
                parserPacket.aroundParser.afterParsingWhere(context, whereClause, elem);

                context = parserPacket.aroundParser.beforeParsingUpdateEntries(context, entries);
                parserPacket.updateEntryParser.parseUpdateEntry(context, entries);
                parserPacket.aroundParser.afterParsingUpdateEntries(context);

                context = parserPacket.aroundParser.afterParsingUpdate(context);
                return context;
        }

        /**
         * remove执行时的解析过程
         *
         * @param context        上下文
         * @param whereClause    条件语句
         * @param parserPacket   解析器包
         * @param <Context>      上下文类型
         * @param <BasicElement> 基本元素类型
         * @param <DS>           数据源类型
         * @return 上下文
         * @throws Exception 可能的异常
         */
        public static <Context, BasicElement, DS> Context removeGenerationProcess(Context context, Where whereClause, ParserPacket<Context, BasicElement, DS> parserPacket) throws Exception {
                context = parserPacket.aroundParser.beforeParsingRemove(context);
                parserPacket.aroundParser.beforeParsingWhere(context, whereClause);
                BasicElement elem = DSUtils.parseWhere(context, whereClause, parserPacket.andOrParser, parserPacket.conditionResolver, parserPacket.expressionResolver);
                parserPacket.aroundParser.afterParsingWhere(context, whereClause, elem);

                context = parserPacket.aroundParser.afterParsingRemove(context);
                return context;
        }

        /**
         * 解析"带取字段"的查询条件
         *
         * @param context              上下文
         * @param qpwf                 查询条件
         * @param aroundParser         全局解释器
         * @param queryParameterParser 查询参数解释器
         * @param <Context>            上下文
         * @param <BasicElement>       基本元素
         * @param <DS>                 数据源类型
         * @throws Exception 可能的异常
         */
        public static <Context, BasicElement, DS> void parseQueryParameterWithFocus(Context context,
                                                                                    QueryParameterWithFocus qpwf,
                                                                                    AroundParser<Context, BasicElement, DS> aroundParser,
                                                                                    QueryParameterParser<Context, BasicElement> queryParameterParser) throws Exception {
                aroundParser.beforeParsingFocusPart(context, qpwf);
                queryParameterParser.focus(context, qpwf.focusMap);
                aroundParser.afterParsingFocusPart(context);
        }

        /**
         * 解析where子句
         *
         * @param context            上下文
         * @param where              where子句
         * @param andOrParser        与,或解释器
         * @param conditionResolver  条件处理
         * @param expressionResolver 表达式处理
         * @param <Context>          上下文类型
         * @param <BasicElement>     基本元素类型
         * @return 生成的基本元素
         * @throws Exception 可能的异常
         */
        public static <Context, BasicElement> BasicElement parseWhere(Context context,
                                                                      Where where,
                                                                      AndOrParser<Context, BasicElement> andOrParser,
                                                                      ConditionResolver<Context, BasicElement> conditionResolver,
                                                                      ExpressionResolver<Context, BasicElement> expressionResolver) throws Exception {
                if (where.isAnd()) {
                        // AND
                        And and = (And) where;
                        context = andOrParser.beforeParsingAnd(context, and);
                        List<BasicElement> elems = new ArrayList<BasicElement>();
                        for (Or or : and.getOrList()) {
                                BasicElement elem = parseWhere(context, or, andOrParser, conditionResolver, expressionResolver);
                                if (elem != null) {
                                        elems.add(elem);
                                }
                        }
                        BasicElement elem = andOrParser.and(context, and.getConditionList(), and.getExpBoolList());
                        if (elem != null) {
                                elems.add(elem);
                        }

                        return andOrParser.afterParsingAnd(context, elems.size() == 0 ? null : andOrParser.and(context, elems));
                } else if (where.isCondition()) {
                        // CONDITION
                        return conditionResolver.resolve(context, (Condition) where);
                } else if (where.isExpression()) {
                        // EXP
                        return expressionResolver.resolve(context, (IExpression) where);
                } else if (where.isOr()) {
                        // OR
                        Or or = (Or) where;
                        context = andOrParser.beforeParsingOr(context, or);
                        List<BasicElement> elems = new ArrayList<BasicElement>();
                        for (And and : or.getAndList()) {
                                BasicElement elem = parseWhere(context, and, andOrParser, conditionResolver, expressionResolver);
                                if (elem != null) {
                                        elems.add(elem);
                                }
                        }
                        BasicElement elem = andOrParser.or(context, or.getConditionList(), or.getExpBoolList());
                        if (elem != null) {
                                elems.add(elem);
                        }

                        return andOrParser.afterParsingOr(context, elems.size() == 0 ? null : andOrParser.or(context, elems));
                } else {
                        throw new IllegalArgumentException("Unknown where type");
                }
        }

        /**
         * 解析查询参数
         *
         * @param context              上下文
         * @param queryParameter       查询参数
         * @param queryParameterParser 查询参数解释器
         * @param <Context>            上下文类型
         * @param <BasicElement>       基本元素类型
         * @throws Exception 可能的异常
         */
        public static <Context, BasicElement> void parseQueryParameter(Context context,
                                                                       QueryParameter queryParameter,
                                                                       QueryParameterParser<Context, BasicElement> queryParameterParser) throws Exception {
                if (queryParameter != null) {
                        Map<QueryParameterTypes, Object[]> parameters = queryParameter.parameters;
                        for (QueryParameterTypes type : parameters.keySet()) {
                                Object[] objArr = parameters.get(type);
                                if (type == QueryParameterTypes.limit) {
                                        queryParameterParser.limit(context, (Integer) objArr[0], (Integer) objArr[1]);
                                } else if (type == QueryParameterTypes.orderBy) {
                                        queryParameterParser.orderBy(context, (OrderBase[]) objArr);
                                } else if (type == QueryParameterTypes.top) {
                                        queryParameterParser.top(context, (Integer) objArr[0]);
                                } else if (type == QueryParameterTypes.distinct) {
                                        queryParameterParser.distinct(context);
                                }
                        }
                }
        }

        /**
         * 解释select过程(会被listGeneration和projectionGeneration调用)
         *
         * @param context              上下文
         * @param whereClause          条件语句
         * @param parameter            查询参数
         * @param aroundParser         全局解释器
         * @param andOrParser          与,或解释器
         * @param conditionResolver    条件处理
         * @param expressionResolver   表达式处理
         * @param queryParameterParser 查询参数解释器
         * @param <Context>            上下文类型
         * @param <BasicElement>       基本元素类型
         * @param <DS>                 数据源类型
         * @return 上下文
         * @throws Exception 可能的异常
         */
        public static <Context, BasicElement, DS> Context parseSelectOperation(Context context,
                                                                               Where whereClause,
                                                                               QueryParameter parameter,
                                                                               AroundParser<Context, BasicElement, DS> aroundParser,
                                                                               AndOrParser<Context, BasicElement> andOrParser,
                                                                               ConditionResolver<Context, BasicElement> conditionResolver,
                                                                               ExpressionResolver<Context, BasicElement> expressionResolver,
                                                                               QueryParameterParser queryParameterParser) throws Exception {
                context = aroundParser.beforeParsingWhere(context, whereClause);
                BasicElement elem = null;
                if (whereClause != null) {
                        elem = parseWhere(context, whereClause, andOrParser, conditionResolver, expressionResolver);
                }
                aroundParser.afterParsingWhere(context, whereClause, elem);
                context = aroundParser.beforeParsingQueryParameter(context, parameter);
                parseQueryParameter(context, parameter, queryParameterParser);
                aroundParser.afterParsingQueryParameter(context);
                return context;
        }
}
